#pragma once


#include <string>
#include <functional>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <MSWSock.h>
#include <windows.h>

#pragma comment(lib, "ws2_32.lib")

namespace std
{
#ifdef UNICODE
	typedef wstring tstring;
#else	
	typedef string tstring;
#endif
}

struct __declspec(novtable) IStreamBuffer
{
	virtual void	Write(size_t len) = 0;
	virtual void	Write(char* data, size_t len) = 0;
	virtual void	Read(char* data, size_t len) = 0;
	virtual void	Read(size_t len) = 0;
	virtual char*	GetRaw() = 0;
	virtual size_t	GetReadOffset() = 0;
	virtual size_t	GetLength() = 0;
	virtual void	Release() = 0;
};

namespace Helper
{
	bool	WSAStartup();
	void	WSACleanup();
	SOCKET	WSAListen(const std::tstring& ip, WORD port, int backlog);
	void	WSAStringToAddress(const std::tstring& ip, WORD port, __out SOCKADDR_IN& sockaddr, __out int& addressSize);
	bool	AcceptEx( SOCKET listenSocket, SOCKET clientSocket, OVERLAPPED& overlapped, IStreamBuffer& streamBuffer);
	bool	DisconnectEx(SOCKET socket, OVERLAPPED& overlapped, DWORD flags);
	bool	ConnectEx( SOCKET socket, const std::tstring& ip, WORD port, OVERLAPPED& overlapped);
	size_t	GetAcceptStreamBufferLen();
}



struct StreamBuffer
{
	static IStreamBuffer*	CreateComponent();
};

typedef std::tr1::function<void (SOCKET, DWORD)> ON_CONNECT_FUNCTOR;
typedef std::tr1::function<void (SOCKET)> ON_ACCEPT_FUNCTOR;
typedef std::tr1::function<void (SOCKET)> ON_DISCONNECT_FUNCTOR;
typedef std::tr1::function<void (SOCKET, IStreamBuffer*)> ON_RECV_FUNCTOR;

struct __declspec(novtable) INetworkLib
{
	virtual bool	Initialize(ON_CONNECT_FUNCTOR onConnect		
							, ON_ACCEPT_FUNCTOR onAccept
							, ON_DISCONNECT_FUNCTOR onDisconnect
							, ON_RECV_FUNCTOR onRecv							
							) = 0;

	virtual bool	Connect(const std::tstring& ip, WORD port) = 0;

	virtual bool	Send(SOCKET socket, IStreamBuffer& stream) = 0;

	virtual bool	Disconnect(SOCKET socket) = 0;

	virtual bool	Listen(const std::tstring& ip, WORD port, int backlog) = 0;

	virtual void	Release() = 0;
};

struct BlockingModelLib
{
	static INetworkLib*	CreateComponent();
};

struct SelectModelLib
{
	static INetworkLib* CreateComponent();
};

struct WSAAsyncSelectModelLib
{
	static INetworkLib* CreateComponent();
};

struct WSAEventSelectModelLib
{
	static INetworkLib* CreateComponent();
};

struct OverlappedCompletionRoutineModelLib
{
	static INetworkLib* CreateComponent();
};

struct OverlappedEventNotificationModelLib
{
	static INetworkLib* CreateComponent();
};

struct OverlappedIOCPModelLib
{
	static INetworkLib* CreateComponent();
};

struct IAsyncSendQueue;
typedef std::tr1::function<void (SOCKET)> DISCONNECT_FUNCTOR;
typedef std::tr1::function<WSAOVERLAPPED* (SOCKET)> WSAOVERLAPPED_CREATE_FUNCTOR;

struct AsyncSendQueueForSelectModel
{
	static IAsyncSendQueue* CreateComponent(DISCONNECT_FUNCTOR disconnectFunctor);
};

struct AsyncSendQueueForOverlappedModel
{
	static IAsyncSendQueue* CreateComponent(DISCONNECT_FUNCTOR disconnectFunctor, WSAOVERLAPPED_CREATE_FUNCTOR wsaoverlappedCreateFunctor, LPWSAOVERLAPPED_COMPLETION_ROUTINE completionRoutine);
};